/*
* v4l.h Video4Linux management
* Copyright (C) 2001 Charles Yates <charles.yates@pandora.be>
* Copyright (C) 2001-2007 Dan Dennedy <dan@dennedy.org>
* Copyright (C) 2007 Stéphane Brunner <stephane.brunner@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#ifndef _KINO_V4L_H
#define _KINO_V4L_H

#include <vector>
using std::vector;
#include <deque>
using std::deque;

#include <string>

#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

#include <time.h>
#include <sys/time.h>

#define _DEVICE_H_
#define _LINUX_TIME_H
#include <linux/videodev.h>

#include <libdv/dv.h>
#include "displayer.h"

/** Abstract V4L Structure class. Provides a wrapping for a video4linux struct.
*/

class V4LStruct
{
public:
	virtual ~V4LStruct() {}
	virtual void *getStruct() = 0;
};

/** Abstract V4L Device class.
*/

class V4LDevice
{
public:
	virtual ~V4LDevice() {}
	virtual int getHandle() = 0;
	bool request( int req, V4LStruct *v4l );
	bool request( int req, void *addr );
};

/** Wrapping for the V4L capabilities structure.
*/

class V4LCapability : public V4LStruct
{
private:
	struct video_capability capability;

public:
	V4LCapability( V4LDevice *device );
	virtual ~V4LCapability();
	void *getStruct();
	char *getName();
	int getNumberOfChannels();
	int getNumberOfAudioDevices();
	int getMinWidth();
	int getMinHeight();
	int getMaxWidth();
	int getMaxHeight();
	bool canCapture();
	bool hasTuner();
	bool hasChromakey();
	bool hasClipping();
	bool hasOverwrite();
	bool hasScaling();
	bool isMonochrome();
	bool canSubCapture();
};

class V4LTuner : public V4LStruct
{
private:
	V4LDevice *device;
	struct video_tuner tuner;

public:
	V4LTuner( V4LDevice *device, int index );
	void *getStruct();
	int getRangeLow();
	void setRangeLow( int low );
	int getRangeHigh();
	void setRangeHigh( int high );
	int getFlags();
	void setFlags( int flags );
	int getMode();
	void setMode( int mode );
	int getSignal();
};

class V4LChannel : public V4LStruct
{
private:
	V4LDevice *device;
	struct video_channel channel;
	vector <V4LTuner *> tuners;
	V4LTuner *current;

public:
	V4LChannel( V4LDevice *device, int index );
	virtual ~V4LChannel();
	void *getStruct();
	char *getName();
	bool setTuner( unsigned int index );
	unsigned int getNumberOfTuners();
	V4LTuner *getTuner( unsigned int index );
	int getSignal();
};

class V4LFrame : public V4LStruct
{};

class V4L : public V4LDevice
{
private:
	int fd;
	vector <V4LChannel *> channels;
	V4LChannel *current;
	int width;
	int height;
	void *map;
	struct video_mmap frame[ 32 ];
	int frame_maps;
	int frame_next;
	int size;
	int frames;
	long long starttime;
	char *device;
	char *input;
	int sample;
	int fps;
public:
	char *audio;
	V4LCapability *capability;
	V4L();
	virtual ~V4L();
	void setInfo( char *device, char *input, char *audio, int sample );
	bool openDevice();
	bool deviceAvailable();
	int getHandle();
	unsigned int getNumberOfChannels();
	V4LChannel *getChannel( unsigned int );
	bool setChannel( unsigned int channel );
	unsigned int getNumberOfTuners();
	V4LTuner *getTuner( unsigned int );
	bool setTuner( unsigned int tuner );
	bool setCaptureResolution( int width, int height );
	int getWidth();
	int getHeight();
	void startAudio();
	void stopAudio();
	bool initialiseCapture( int format );
	void *getNextFrame();
	void stopCapture();
	int getFrequency();
	bool setFrequency( int frequency );
	int getSignal();
	int mappedMemorySize( bool init = false );
	int frameSample;
};

class EncoderFrame
{
public:
	uint8_t *image;
	int width;
	int height;

	unsigned char audio[ 10240 ];
	int length;

	EncoderFrame();
	~EncoderFrame();
	void setVideo( void *, int, int );
};

class DvEncoder
{
private:
	unsigned char data[ 144000 ];
	dv_encoder_t *encoder;
	FILE *p;
	static deque < EncoderFrame * > used;
	static deque < EncoderFrame * > available;
	bool active;
	pthread_t thread;
	pthread_mutex_t mutex;
	char *filename;
	int width;
	int height;
public:
	char *audio;
	DvEncoder( char *, int, int );
	~DvEncoder();
	EncoderFrame *getFrame();
	void doneWithFrame( EncoderFrame * );
	static void *startThread( void * );
	void writeThread();
};

/** GDK Extension of V4L that takes care of presentation issues.
 
  	Up to this point, the V4L classes have been independent of the 
	presentation.
*/

class GDKV4L : public V4L
{
private:
	// Displayer information
	Displayer *displayer;
//	DisplayerInput input;

public:
	GDKV4L();
	virtual ~GDKV4L();
	void startVideo();
	void startCapturing();
	void stopVideo();
	void stopCapturing();
	void draw();
	void capture( DvEncoder * );
	bool active;
	bool capturing;
};

#endif
